/*******************************************************************************
SceneKit.cpp

	Author:		LiuDingXi
	e-mail:		liudx@gmail.com
	Date time:	2009-08-07

	Copyright (C) 2009
	All rights reserved.
	
*******************************************************************************/
#include "StdAfx.h"
#include "SceneKit.h"
#include "SceneDat.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

////////////////////////////////////////////////////////////////////////////////

CSceneKit::CSceneKit()
{
}

CSceneKit::~CSceneKit()
{
	Free();
}

BOOL CSceneKit::LoadSight(LPCTSTR szFileName, SINT nLoadDelay)
{
	LPCTSTR pExt = PathFindExtension(szFileName);
	if(pExt)
	{
		if(_tcsicmp(pExt, _T(".sgt")) == 0)
		{
			SIGHT* pSight = new SIGHT;
			pSight->szFile = PathFindFileName(szFileName);
			pSight->nLoadDelay = nLoadDelay;
			m_SightList.push_back(pSight);

			CFile file(szFileName, CFile::modeRead);
			CArchive arSight(&file, CArchive::load);
			return pSight->Load(arSight);
		}
	}
	return FALSE;
}

BOOL CSceneKit::Load(LPCTSTR szFolder, LPCTSTR szScene)
{
	if(szScene)
	{
		TCHAR szFileName[MAX_PATH];
		_tcscpy(szFileName, szFolder);
		TCHAR* pTail = szFileName;
		while(*pTail)
		{
			*pTail++;
		}
		
		LPCTSTR p = szScene;
		MoveToBegin(p);

		if(*p == '{')
		{
			SINT nLoadDelay = 0;
			p++;
			while(*p)
			{
				CString szString = ParseOf(p);
				if(szString == '}')
				{
					break;
				}
				else if(szString.Find('(') != -1)
				{
					szString.Replace("(", NULL);
					szString.Replace(")", NULL);
					nLoadDelay = atoi(szString);
				}
				else
				{
					*pTail = 0;
					PathAppend(szFileName, szString);
					if(!LoadSight(szFileName, nLoadDelay))
					{
						printf("Load Sight %s Error\n", szString);
						return FALSE;
					}
					nLoadDelay = 0;
				}
			}
			return TRUE;
		}
	}
	return FALSE;
}

BOOL CSceneKit::Load(CArchive& ar)
{
	TCHAR szFolder[MAX_PATH];
	 _tcscpy(szFolder, ar.GetFile()->GetFilePath());
	 LPTSTR pTail = PathFindFileName(szFolder);
	 if(pTail)
	 {
		LPCTSTR p = pTail;		 
		while(*p && *p != _T('.'))
		{
			m_szName += *p++;
		}

		 *pTail = 0;

	 }
	 m_szFolder = szFolder;

	CString s;
	while(ar.ReadString(s))
	{
		if(s.IsEmpty())
			continue;
		
		LPCTSTR p = s;
		MoveToBegin(p);
		
		#define IS_TAG(tag)	_tcsnicmp(p, tag, _tcslen(tag)) == 0
		
		if(IS_TAG(_T("import")))
		{
			p += 6;
			CString szFile = ParseOf(p);

			SINT nLoadDelay = ParseOf(p, 0);

			TCHAR szFileName[MAX_PATH];
			_tcscpy(szFileName, szFolder);
			PathAppend(szFileName, szFile);

			if(!LoadSight(szFileName, nLoadDelay))
			{
				printf("Load Sight %s Error\n", szFile);
				return FALSE;
			}
		}
		else if(IS_TAG(_T("name")))
		{
			p += 4;
			m_szName = ParseOf(p);
		}
	}	
	return TRUE;
}

BOOL CSceneKit::Store(CArchive& ar)
{
	return TRUE;
}

BOOL CSceneKit::Free()
{
	// generate codes
	if(m_SightList.size() > 0)
	{
		list<SIGHT*>::iterator it;
		it = m_SightList.begin();
		while(it != m_SightList.end())
		{
			SIGHT* pSight = *it++;
			delete pSight;
		}
		m_SightList.clear();
	}
	return TRUE;
}

BOOL CSceneKit::Build(LPCTSTR szOutput)
{
	CCoder Coder;

	Coder.SetFolder(szOutput);

	CString szName = m_szName;

	TCHAR szSaveFile[MAX_PATH];
	_tcscpy(szSaveFile, szOutput);
	PathAppend(szSaveFile, szName+_T(".scene"));
	SaveDat(szSaveFile);

	if(!Coder.HasSrcFile(szName))
	{
		Coder.TemplateFor(_T("scene"), _T("SceneX"), szName, szName);
	}

	Coder.Load(szName + _T(".h"));

	// generate codes
	if(m_SightList.size() > 0)
	{
		CString szMaps;
		szMaps = _T("\tenum {\r\n");

		CString szSprites;
		szSprites = _T("\tenum {\r\n");

		CString szDialogs;
		szDialogs = _T("\tenum {\r\n");

		int iSight = 0;

		list<SIGHT*>::iterator it;
		it = m_SightList.begin();
		while(it != m_SightList.end())
		{
			SIGHT* pSight = *it++;

			pSight->Build(szOutput, iSight, szMaps, szSprites, szDialogs);
			iSight++;
		}

		szMaps += _T("\t};\r\n");
		Coder.LnRemove(_T("MAP_INDEX_BEGIN"), _T("MAP_INDEX_END"));
		Coder.LnInsert(_T("MAP_INDEX_BEGIN"), szMaps);

		szSprites += _T("\t};\r\n");
		Coder.LnRemove(_T("SPRITE_INDEX_BEGIN"), _T("SPRITE_INDEX_END"));
		Coder.LnInsert(_T("SPRITE_INDEX_BEGIN"), szSprites);

		szDialogs += _T("\t};\r\n");
		Coder.LnRemove(_T("DIALOG_INDEX_BEGIN"), _T("DIALOG_INDEX_END"));
		Coder.LnInsert(_T("DIALOG_INDEX_BEGIN"), szDialogs);
	}

	Coder.Save(szName + _T(".h"));

	return TRUE;
}

BOOL CSceneKit::SaveDat(LPCTSTR szFileName)
{
	try
	{
		using namespace SceneDat;

		CFile file(szFileName, CFile::modeCreate|CFile::modeWrite);

		SCENE_HEAD Head;
		Head.dwMark = SCENE_MARK;
		Head.nSights = m_SightList.size();

		file.Write(&Head, sizeof(Head));

		typedef SceneDat::SIGHT_LOAD SLOAD;
		SLOAD* pSload = new SLOAD[Head.nSights];

		int nSloadSize = sizeof(SLOAD)*Head.nSights;
		SceneDat::PTR nOffset = sizeof(Head) + nSloadSize;

		int iSight = 0;
		int nMaxSize = 0;

		int N_EXT = strlen(SIGHT_EXT);

		list<SIGHT*>::iterator it;
		it = m_SightList.begin();
		while(it != m_SightList.end())
		{
			SIGHT* pSight = *it++;

			pSload[iSight].nDelay = pSight->nLoadDelay;
			pSload[iSight].pSight = nOffset;

			int nLen =  pSight->m_szName.GetLength();
			int nSize = sizeof(TCHAR) * (nLen + N_EXT + 1);
			nSize = (nSize/4 + 1) * 4;
			if(nSize > nMaxSize)
			{
				nMaxSize = nSize;
			}
			nOffset += nSize;
			iSight++;
		}
		
		file.Write(pSload, nSloadSize);

		if(nMaxSize > 0)
		{
			BYTE* pBuffer = new BYTE[nMaxSize];

			it = m_SightList.begin();
			while(it != m_SightList.end())
			{
				SIGHT* pSight = *it++;

				int nLen =  pSight->m_szName.GetLength();
				int nSize = sizeof(TCHAR) * (nLen + N_EXT+ 1);
				nSize = (nSize/4 + 1) * 4;

				memset(pBuffer, 0, nMaxSize);
				strcpy((char*)pBuffer, (LPCSTR)(pSight->m_szName));
				strcat((char*)pBuffer, SIGHT_EXT);

				file.Write(pBuffer, nSize);
			}

			delete[] pBuffer;
		}

		delete[] pSload;

		file.Close();
		return TRUE;
	}
	catch(CException* e)
	{
		e->ReportError();
		e->Delete();
		return FALSE;
	}
}